use std::{
    sync::{mpsc, Arc, Mutex},
    thread::{self, JoinHandle},
};

const REQUEST_INDEX: &str = "GET / HTTP/1.1";
const RESPONSE_INDEX: &str = "GET / HTTP/1.1";

pub struct ThreadPool {
    workers: Vec<Option<Worker>>,
    sender: mpsc::Sender<Message>,
}
type Job = Box<dyn FnOnce() + 'static + Send>;
enum Message {
    NewJob(Job),
    Tterminal,
}
struct Worker {
    id: usize,
    thread: Option<JoinHandle<()>>,
}
impl ThreadPool {
    pub fn new(num: usize) -> ThreadPool {
        let (sender, receiver) = mpsc::channel();
        let receiver = Arc::new(Mutex::new(receiver));
        let workers = (0..=num)
            .map(|id| Some(Worker::new(id, Arc::clone(&receiver))))
            .collect::<Vec<Option<Worker>>>();
        ThreadPool { workers, sender }
    }
    pub fn execable<F: FnOnce() + 'static + Send>(&self, f: F) {
        self.sender.send(Message::NewJob(Box::new(f))).unwrap();
    }
}
impl Drop for ThreadPool {
    fn drop(&mut self) {
        // 发送所以线程关闭信号
        (&mut self.workers).into_iter().for_each(|_f| {
            self.sender.send(Message::Tterminal).unwrap();
        });
        // 关闭所有线程
        for work in &mut self.workers {
            if let Some(thread) = work.take() {
                thread.thread.unwrap().join().unwrap();
            }
        }
    }
}
impl Worker {
    fn new(id: usize, receiver: Arc<Mutex<mpsc::Receiver<Message>>>) -> Worker {
        let thread = Some(thread::spawn(move || loop {
            let message = receiver.lock().unwrap().recv().unwrap();
            match message {
                Message::NewJob(job) => {
                    println!("{}--start--{}", id, id);
                    job()
                }
                Message::Tterminal => {
                    println!("{}--thread over--{}", id, id);
                    break;
                }
            }
        }));
        Worker { id, thread }
    }
}
